/**
 * 性能剖析工具
 */
function Profile(){
	this._methods = {};  //统计类方法调用次数、执行时间等数据用的哈希
	this._callstack = [];  //模拟调用栈
	this._loging = false;  //日志锁，决定是否输出日志
	this._disabled = true;  //是否禁用日志记录
}
(function(){
	this._skipKeys = {
		"_clazz"      : 1,
	//"_init"       : 1,
	//"dispose"     : 1,
	//"onTouchStart": 1,
		"onTouchMove" : 1,
	//"onTouchEnd"  : 1,
		"appendLog"   : 1,
		"------------": 1
	};
	this._skipMethods = {
		"WebRuntime::log": 1
	};
	this.createMethod = function(profile, id){
		return function(){
			return profile.callMethod(id, this, arguments);
		};
	};
	/**
	 * 骇客一个类，把其原型上的方法全部替换掉
	 * @param {Class} clazz 要剖析的类
	 * @param {Object} proto 类的原型
	 */
	this.hackClass = function(clazz, proto){
		var re_proto = RegExp.prototype;
		for(var k in proto){
			var m = proto[k];
			if(k in this._skipKeys) continue;
			//修正: safari,chrome下 typeof /a/g === "function" 的问题
			if(typeof m == "function" && m.__proto__ !== re_proto && !("__id" in m)){  //是方法且没有hack过
				var id = clazz._className + "::" + k;  //方法名
				if(id in this._skipMethods) continue;
				proto[k] = this.createMethod(this, id);  //替换掉原始方法
				proto[k].__id = id;  //标记已经hack过了
				this._methods[id] = {
					"id"    : id,  //方法id标识
					"method": m,   //原始方法
					"mm"    : {},  //内部调用的其他方法
					"count" : 0,   //执行次数
					"time"  : 0    //累计执行时间
				};
			}
		}
	};
	/**
	 * 调用对象真实的方法，并正确传递参数
	 * @param {String} id 方法id标识
	 * @param {Object} obj 方法所属对象
	 * @param {Array} args 传给方法的参数数组
	 */
	this.callMethod = function(id, obj, args){
		//var id = args.callee.__id;
		var m = this._methods[id];
		var p;
		if(this._callstack.length > 0){
			p = this._callstack[this._callstack.length - 1];
			var mm = p.mm;
			if(id in mm){
				mm[id]++;
			}else{
				mm[id] = 1;
			}
		}
		if(!this._loging && !this._disabled){
			this.logCall(id, args);  //输出调用日志
		}
		this._callstack.push(m);
		m["count"]++;  //执行次数增量
		var t0 = new Date().getTime();
		var ret;
		try{
			ret = m["method"].apply(obj, args);  //执行原始方法
		}catch(ex){
			window.alert(
				"method=" + id + ","
				+ "\nclassName=" + obj._className + ","
				+ "\nmessage=" + ex.message
			);
		}
		var t = new Date().getTime() - t0;
		m["time"] += t;  //累计执行时间
		if(p){
			p["time"] -= t;  //把对调用者的时间影响去掉
		}
		this._callstack.pop();
		return ret;
	};
	this.sort = function(key){
		var a = [];
		for(var k in this._methods){
			a.push(this._methods[k]);
		}
		a.sort(function(a, b){
			return b[key] - a[key];
		});
		return a;
	};
	this.getData = function(key){
		var sb = [];
		var arr = this.sort(key);
		for(var i = 0, len = arr.length; i < len; i++){
			var a = arr[i];
			sb.push("{id:\"" + a.id + "\",count:" + a.count + ",time:" + a.time + "}");
		}
		return "[" + sb.join(",") + "]";
	};
	this.logCall = function(id, args){
		this._loging = true;
		if(window.__runtime__){
			var sb = [];
			for(var i = 0, len = args.length; i < len; i++){
				sb.push(typeof(args[i]));
			}
			console.log("call " + id + "(" + sb.join(",") + ")");
			//__runtime__.log("call " + id + "(" + sb.join(",") + ")");
		}
		this._loging = false;
	};
}).apply(Profile.prototype);